﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using Mvc.XForms.UI.Settings;
using Mvc.XForms.Utilities;

namespace Mvc.XForms.UI {
	public class Grid<T> : IGrid<T> {
		private string paging;

		public GridSettings<T> Settings { get; protected set; }
		public IGridFormatter Formatter { get; set; }
		public IPagerFormatter PagerFormatter { get; set; }
		public IGridHead<T> Head { get; protected set; }
		public IEnumerable<T> Items { get; protected set; }
		public IPaged Paged { get; protected set; }
		public ISorted Sorted { get; protected set; }
		public HttpContextBase HttpContext { get; protected set; }
		public bool IsPaged { get; set; }
		public string PagedUrlTemplate { get; protected set; }
		public string SortedUrlTemplate { get; protected set; }

		public Action<T> BodyAction { get; set; }
		public Action<IGridHead<T>> HeadAction { get; set; }
		public Action NoResultHtml { get; set; }
		public PagerPosition PagerPosition { get; set; }

		public Grid(HttpContextBase httpContext, IPagedSortedList<T> pagedSortedList)
			: this(httpContext, pagedSortedList.Items, pagedSortedList, pagedSortedList) { }

		public Grid(HttpContextBase httpContext, IPagedList<T> pagedList)
			: this(httpContext, pagedList.Items, pagedList, null) { }

		public Grid(HttpContextBase httpContext, ISortedList<T> sortedList)
			: this(httpContext, sortedList.Items, null, sortedList) { }

		public Grid(HttpContextBase httpContext, IEnumerable<T> items) {
			Init(httpContext, items, null, null);
		}

		public Grid(HttpContextBase httpContext, IEnumerable<T> items, IPaged paged) {
			Init(httpContext, items, paged, null);
		}

		public Grid(HttpContextBase httpContext, IEnumerable<T> items, ISorted sorted) {
			Init(httpContext, items, null, sorted);
		}

		public Grid(HttpContextBase httpContext, IEnumerable<T> items, IPaged paged, ISorted sorted) {
			Init(httpContext, items, paged, sorted);
		}

		protected virtual void Init(HttpContextBase httpContext, IEnumerable<T> items, IPaged paged, ISorted sorted) {
			Items = items;
			Paged = paged;
			Sorted = sorted;

			HttpContext = httpContext;
			Formatter = GridFormatterFactory.Current.Formatter;
			PagerFormatter = GridFormatterFactory.Current.PagerFormatter;
			Settings = new GridSettings<T>(this);
			Head = new GridHead<T>(this);

			if (Paged != null) PagedUrlTemplate = InitPagedUrlTemplate();
			if (Sorted != null) SortedUrlTemplate = InitSortedUrlTemplate();
		}

		public virtual void Render() {
			if (NoResultHtml != null && Items.Count() == 0)
				NoResultHtml();
			else
				RenderGrid();
		}

		protected virtual void RenderGrid() {
			if (IsPaged && PagerPosition != PagerPosition.Bottom)
				RenderPaging();

			HttpContext.Response.Write(Formatter.GridStart());

			if (HeadAction != null)
				RenderHead();

			RenderBody();

			HttpContext.Response.Write(Formatter.GridEnd());

			if (IsPaged && PagerPosition != PagerPosition.Top)
				RenderPaging();
		}

		protected virtual void RenderBody() {
			HttpContext.Response.Write(Formatter.BodyStart());
			
			Items.ForEach((item, index) => {
				HttpContext.Response.Write(Formatter.BodyRowStart(index));
				BodyAction(item);
				HttpContext.Response.Write(Formatter.BodyRowEnd(index));
			});

			HttpContext.Response.Write(Formatter.BodyEnd());
		}

		protected virtual void RenderHead() {
			HttpContext.Response.Write(Formatter.HeadStart());
			HeadAction(Head);
			HttpContext.Response.Write(Formatter.HeadEnd());
		}

		protected virtual void RenderPaging() {
			HttpContext.Response.Write(Paging());
		}

		protected virtual string Paging() {
			if (paging != null)
				return paging;

			paging = PagerFormatter.Pager(Paged, PagedUrlTemplate);
			return paging;
		}

		private string InitPagedUrlTemplate() {
			if (Paged == null)
				throw new InvalidOperationException("Cannot use paging, grid data does not implement IPaged.");

			var varsToReplace = new string[] { Paged.PageIndexKey };
			return HttpContext.Request.UrlFormat(varsToReplace, true);
		}

		private string InitSortedUrlTemplate() {
			if (Sorted == null)
				throw new InvalidOperationException("Cannot use sorting, grid data does not implement ISorted");

			var varsToReplace = new string[] { Sorted.SortExpressionKey, Sorted.SortDirectionKey };
			return HttpContext.Request.UrlFormat(varsToReplace, true);
		}
	}
}